package com.yunchao.feature.base.domain.result

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

fun <T> Flow<T>.asResult(): Flow<kotlin.Result<T>> =
    map { kotlin.Result.success(it) }.catch { emit(kotlin.Result.failure(it)) }


sealed interface Result<out T> {
    data class Success<T>(val data: T) : Result<T>
    data class Error(val exception: Throwable) : Result<Nothing>
    data object Loading : Result<Nothing>
}

fun <T> Flow<T>.toResult(): Flow<Result<T>> = map<T, Result<T>> { Result.Success(it) }
    .onStart { emit(Result.Loading) }
    .catch { emit(Result.Error(it)) }
/*
inline fun <T, R> ApiResult<T>.handleApiResult(transform: (T?) -> R): kotlin.Result<R> {
    return when (this) {
        is ApiResult.Success -> kotlin.Result.success(transform(this.data))
        is ApiResult.Error -> kotlin.Result.failure(createException(this.message))
        is ApiResult.Exception -> {
            Timber.e(this.throwable)
            kotlin.Result.failure(this.throwable)
        }
    }
}*/

fun <T> kotlin.Result<T>.mapFailure(transform: (Throwable) -> IllegalArgumentException): kotlin.Result<T> {
    return onFailure { throwable ->
        throw transform(throwable)
    }
}



// 自定义异常，表示内部出错了
class InnerException(message: String = "inner value error"): Exception(message)

@OptIn(ExperimentalContracts::class)
inline fun <V, E> kotlin.Result<V>.andThen(transform: (V) -> kotlin.Result<E>): kotlin.Result<E> {
    // kotlin 约定，告诉编译器 transform 最多执行一次
    contract {
        callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
    }
    if (isSuccess) {
        val value = getOrNull() ?: return kotlin.Result.failure(InnerException())
        return transform(value)
    } else {
        val exception = exceptionOrNull() ?: return kotlin.Result.failure(InnerException())
        return kotlin.Result.failure(exception)
    }
}


@OptIn(ExperimentalContracts::class)
inline fun <V, E> kotlin.Result<V>.dispatch(transform: (V) -> E): kotlin.Result<E> {
    contract {
        callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
    }

    if (isSuccess) {
        val value = getOrNull() ?: return kotlin.Result.failure(InnerException())
        return kotlin.runCatching {
            transform(value)
        }
    } else {
        val exception = exceptionOrNull() ?: return kotlin.Result.failure(InnerException())
        return kotlin.Result.failure(exception)
    }
}

@OptIn(ExperimentalContracts::class)
inline fun <V> zip(block: () -> V): kotlin.Result<V> {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return runCatching {
        block()
    }
}


fun <V> kotlin.Result<V>.or(result: kotlin.Result<V>): kotlin.Result<V> {
    return when {
        isSuccess -> this
        else -> result
    }
}



// 获取成功结果的列表
fun <V, R : kotlin.Result<V>> valuesOf(results: List<R>): List<V> {
    return results.asIterable().filterValues()
}

fun <V> Iterable<kotlin.Result<V>>.filterValues(): List<V> {
    return filterValuesTo(ArrayList())
}

fun <V, C : MutableCollection<in V>> Iterable<kotlin.Result<V>>.filterValuesTo(destination: C): C {
    for (element in this) {
        if (element.isSuccess) {
            val value = element.getOrNull() ?: continue
            destination.add(value)
        }
    }
    return destination
}

fun <V> Iterable<kotlin.Result<V>>.allSuccess(): Boolean {
    return all(kotlin.Result<V>::isSuccess)
}

